<?php

class Request
{
    /**
     * @var bool
     */
    protected $_dispatched = 0;

    /**
     * @var Nuo_Controller
     */
    protected $_controller = null;

    /**
     * @var array
     */
    protected $_params = array();

    /**
     * controller short name in lowercase simple only.
     * @return void
     */
    protected $_controllerName = '';

    /**
     * action name lowercase deflected only.
     */
    protected $_actionName = 'index';

    /**
     * process $params
     * @param array $params
     * @param string $controllerName
     * @param string $actionName
     * @return void
     */
    public function __construct($params = null, $controllerName = null, $actionName = null)
    {

        if (!empty($params))
        {
            $this -> setParams($params);
        }

        if (null != $controllerName)
        {
            $this -> setControllerName($controllerName);
        }

        if (null != $actionName)
        {
            $this -> setActionName($actionName);
        }

    }

    /**
     * check is dispatched
     * @return $this
     */
    public function isDispatched()
    {
        return $this -> _dispatched;
    }

    /**
     * set is dispatched
     * @param bool $flag
     * @return Request
     */
    public function setDispatched($flag)
    {
        $this -> _dispatched = (bool)$flag;
        return $this;
    }

    /**
     * @return string
     */
    public function getControllerName()
    {
        return $this -> _controllerName;
    }

    /**
     * @param string $controllerName
     * @return Request
     */
    public function setControllerName($controllerName)
    {
        $this -> _controllerName = strtolower($controllerName);
        return $this;
    }

    /**
     * get action name
     * @return string
     */
    public function getActionName()
    {
        return $this -> _actionName;
    }

    /**
     * @param string $actionName
     * @return Request
     */
    public function setActionName($actionName)
    {

        $this -> _actionName = strtolower($actionName);
        return $this;
    }

    /**
     * @param Controller $controller object
     * @return Request
     */
    public function setController(Controller $controller)
    {
        $this -> _controller = $controller;
        return $this;
    }

    /**
     * @param string $name
     * @param any $default
     * @return any
     */
    public function getParam($name, $default = null)
    {
        if (method_exists($this, $method = 'get' . ucfirst($name)))
        {
            return $this -> {$method}($default);
        }
        return isset($this -> _params[$name]) ? $this -> _params[$name] : $default;
    }

    /**
     * @param string $name
     * @param any $value
     * @return Request
     */
    public function setParam($name, $value)
    {

        if (method_exists($this, $method = 'set' . ucfirst($name)))
        {
            $this -> {$method}($value);
        }
        else
        {
            $this -> _params[$name] = $value;
        }

        return $this;
    }

    /**
     * set all params
     * @param array $params
     * @return Request
     */
    public function setParams($params)
    {

        if (!empty($params))
        {

            foreach ($params as $name => $value)
            {
                $this -> setParam($name, $value);
            }
        }
        return $this;
    }

    /**
     * @return string
     */
    public function getFullActionName()
    {
        return $this -> _controllerName . ':' . $this -> _actionName;
    }

    /**
     * get all params
     * @return array
     */
    public function getParams()
    {
        return $this -> _params;
    }

    /**
     * check params exists
     * @return bool
     */
    public function hasParam($name)
    {
        return isset($this -> _params[$name]);
    }

    /**
     * clear param name
     * @return Zend_Controller_Request
     */
    public function clearParam($name)
    {
        if (method_exists($this, $method = 'clear' . ucfirst($name)))
        {
            $this -> {$method}();
        }
        if (isset($this -> _params[$name]))
        {
            unset($this -> _params[$name]);
        }
        return $this;
    }

    /**
     * clear all params
     * @return Request
     */
    public function clearParams()
    {
        $this -> _params = array();
        $this -> _controllerName = null;
        $this -> _actionName = 'index';
        return $this;
    }

    /**
     * dispatch an action.
     */
    public function dispatch()
    {
        //start buffer before process
        ob_start();

        // return a response result.
        $maxForward = 10;
        do
        {
            /**
             * process.
             */
            $class = Nuo::getControllerClass($this -> _controllerName);

            if (!Nuo::loadClass($class))
            {
                throw new Nuo_Exception("controller [$class] does not exists!");
            }

            $controller = $this -> _controller = new $class($this);

            // try to dispatch this action.
            $controller -> dispatch($this -> _actionName);

        }
        while($this->_dispatched == false && --$maxForward > 0);

        if ($this -> _dispatched == false)
        {
            throw new Nuo_Exception("maximum recursion called, the request still not dispatched!.");
        }

        $format = $this -> getParam('format', null);

        if (null == $format && !$this -> _controller -> isNoRender())
        {
            echo $this -> _controller -> render();
        }
        else
        if ('json' == $format)
        {
            echo Zend_Json::encode((array)$this -> _controller -> data);
        }
        else
        if ('jsonp' == $format)
        {
            echo sprintf('callback(%s);', Zend_Json::endcode((array)$this -> _controller -> data));
        }

        // end buffer
        return ob_get_clean();
    }

    /**
     * magic call dispatch.
     */
    static public function execute($params = null, $controllerName = null, $actionName = null)
    {
        $request = new self($params, $controllerName, $actionName);
        return $request -> dispatch();
    }

}
